// Copyright 2011 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "shell/invoke_command.h"

using testing::HasSubstr;

namespace flame {

//////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////

class InvokeCommandTest : public ::testing::Test {
 protected:
  uint8 Run(const string& command) {
    stdout_.clear();
    stderr_.clear();
    return InvokeCommand(command, &stdout_, &stderr_);
  }

  string stdout_;
  string stderr_;
};

//////////////////////////////////////////////////////
// Tests
//////////////////////////////////////////////////////

TEST_F(InvokeCommandTest, EmptyString) {
  EXPECT_EQ(0, Run(""));
  EXPECT_EQ("", stdout_);
  EXPECT_EQ("", stderr_);
}

TEST_F(InvokeCommandTest, ExitCodes) {
  EXPECT_EQ(0, Run("true"));
  EXPECT_EQ(17, Run("exit 17"));
}

TEST_F(InvokeCommandTest, Arguments) {
  EXPECT_EQ(0, Run("ls /"));
  EXPECT_EQ(1, Run("ls /nonexistent_foo_bar"));
}

TEST_F(InvokeCommandTest, AndOperator) {
  EXPECT_NE(0, Run("true && false"));
  EXPECT_EQ(0, Run("true && true"));
}

TEST_F(InvokeCommandTest, OrOperator) {
  EXPECT_EQ(0, Run("true || false"));
  EXPECT_NE(0, Run("false || false"));
}

TEST_F(InvokeCommandTest, PipeOperator) {
  EXPECT_NE(0, Run("echo 'foo bar' | grep baz"));
  EXPECT_EQ(0, Run("echo 'foo bar' | grep bar"));
}

TEST_F(InvokeCommandTest, Output) {
  const string long_string = string(10e3, 'a');
  const string echo_command = "echo '" + long_string + "'";

  // stdout
  ASSERT_EQ(0, Run(echo_command));
  EXPECT_EQ(long_string + "\n", stdout_);
  EXPECT_EQ("", stderr_);

  // stderr
  ASSERT_EQ(0, Run(echo_command + " 1>&2"));
  EXPECT_EQ("", stdout_);
  EXPECT_EQ(long_string + "\n", stderr_);

  // Both
  Run(echo_command + " && ls /" + long_string);
  EXPECT_EQ(long_string + "\n", stdout_);
  EXPECT_THAT(stderr_, HasSubstr("/" + long_string));
  EXPECT_THAT(stderr_, HasSubstr("name too long"));
}

TEST_F(InvokeCommandTest, UnknownCommand) {
  EXPECT_NE(0, Run("rejigger ./frobnicator"));
  EXPECT_EQ("", stdout_);
  EXPECT_THAT(stderr_, HasSubstr("command not found"));
}

TEST_F(InvokeCommandTest, UnterminatedString) {
  EXPECT_NE(0, Run("echo 'foo"));
  EXPECT_THAT(stderr_, HasSubstr("syntax error"));
}

}  // namespace flame
